#include "vm_type_register.hpp"

#include "data/editor_data.hpp"

#include <wrenbind17/wrenbind17.hpp>

#include "scripting/extra/info_api.hpp"
#include "utils/app_utils.hpp"
#include "utils/date_utils.hpp"
#include "utils/log.hpp"
#include "utils/path_utils.hpp"
#include "utils/shell_utils.hpp"
#include "sql/sql_data_extensions.hpp"

using namespace wrenbind17;

struct System {
    static void CopyText(std::string text)
    {
        ::CopyText(text);
    }

    static void I(std::string msg) { SendInfo(msg); }
    static void W(std::string msg) { SendWarning(msg); }
    static void E(std::string msg) { SendError(msg); }
    static void P(bool show) { ShowProgressDialog(show); }
    static void N(std::string msg, double ms) { SendNotification(msg, ms); }

    static void LogD(std::string msg) { log_printf("<script>", 1, LOG_LEVEL_DEBUG, "%s", msg.c_str()); }
    static void LogI(std::string msg) { log_printf("<script>", 1, LOG_LEVEL_INFO, "%s", msg.c_str()); }
    static void LogW(std::string msg) { log_printf("<script>", 1, LOG_LEVEL_WARN, "%s", msg.c_str()); }
    static void LogE(std::string msg) { log_printf("<script>", 1, LOG_LEVEL_ERROR, "%s", msg.c_str()); }

    static std::string GetIssueProjectDesc(int issue)
    {
        return sql_data_ext.get_issue_project_desc(issue);
    }
};


void RegisterEditorType(VM* vm)
{
    assert(vm != nullptr);

    // std types
    auto &m = vm->module("App");

    // Tag
    auto& c_tag = m.klass<Tag>("Tag");
    c_tag.varReadonly<&Tag::tag_name>("name");
    c_tag.varReadonly<&Tag::tag_level>("level");
    c_tag.varReadonly<&Tag::tag_color>("color");

    // WorkItem
    auto& c_work_item = m.klass<WorkItem>("WorkItem");
    c_work_item.varReadonly<&WorkItem::create_date>("create_date");
    c_work_item.varReadonly<&WorkItem::hour>("hour");
    c_work_item.varReadonly<&WorkItem::comment>("comment");
    c_work_item.varReadonly<&WorkItem::note>("note");
    c_work_item.varReadonly<&WorkItem::issue_id>("issue");
    c_work_item.varReadonly<&WorkItem::act_id>("act");

    // Vector<Tag>
    StdVectorBindings<Tag>::bind(m, "VecTag");

    // ItemNode
    auto &c_item_node = m.klass<ItemNode>("ItemNode");
    c_item_node.varReadonly<&ItemNode::item>("item");
    c_item_node.varReadonly<&ItemNode::item_tags>("tags");

    // List<ItemNode>
    StdListBindings<ItemNode>::bind(m, "ListItemNode");

    // DayLevelNode
    auto& c_day_level_node = m.klass<DayLevelNode, ExpandableNodeBase<ItemNode>>("DayLevelNode");
    c_day_level_node.func<&DayLevelNode::LoadInnerData>("load");
    c_day_level_node.varReadonly<&DayLevelNode::title>("title");
    c_day_level_node.varReadonly<&DayLevelNode::children>("children");
    c_day_level_node.varReadonly<&DayLevelNode::child_key>("key");

    // List<DayLevelNode>
    StdListBindings<DayLevelNode>::bind(m, "ListDayLevelNode");

    // MonthLevelNode
    auto& c_month_level_node = m.klass<MonthLevelNode, ExpandableNodeBase<DayLevelNode>>("MonthLevelNode");
    c_month_level_node.func<&MonthLevelNode::LoadInnerData>("load");
    c_month_level_node.varReadonly<&MonthLevelNode::title>("title");
    c_month_level_node.varReadonly<&MonthLevelNode::children>("children");
    c_month_level_node.varReadonly<&MonthLevelNode::child_key>("key");

    // List<MonthLevelNode>
    StdListBindings<MonthLevelNode>::bind(m, "ListMonthLevelNode");

    // YearLevelNode
    auto& c_year_level_node = m.klass<YearLevelNode, ExpandableNodeBase<MonthLevelNode>>("YearLevelNode");
    c_year_level_node.func<&YearLevelNode::LoadInnerData>("load");
    c_year_level_node.varReadonly<&YearLevelNode::title>("title");
    c_year_level_node.varReadonly<&YearLevelNode::children>("children");
    c_year_level_node.varReadonly<&YearLevelNode::child_key>("key");

    auto& c_sys = m.klass<System>("AppFunc");
    // clipboard function
    c_sys.funcStatic<&System::CopyText>("CopyText");

    // version
    c_sys.funcStatic<&GetAppVersionText>("AppVersionStr");
    c_sys.funcStatic<&GetAppVersionInfo>("AppVersionInfo");
    c_sys.funcStatic<&GetAppVersionCode>("AppVersionCode");
    c_sys.funcStatic<&GetDataVersion>("DataVersionStr");
    c_sys.funcStatic<&GetDataVersionCode>("DataVersionCode");

    // info dialog
    c_sys.funcStatic<&System::I>("ShowInfo");
    c_sys.funcStatic<&System::W>("ShowWarning");
    c_sys.funcStatic<&System::E>("ShowError");
    c_sys.funcStatic<&System::P>("ShowProgress");

    // status message
    c_sys.funcStatic<&System::N>("Notification");

    // logging
    c_sys.funcStatic<&System::LogD>("LogD");
    c_sys.funcStatic<&System::LogI>("LogI");
    c_sys.funcStatic<&System::LogW>("LogW");
    c_sys.funcStatic<&System::LogE>("LogE");

    // path utils
    c_sys.funcStatic<&GetTempFilePath>("TempPath");
    c_sys.funcStatic<&GetAssetsPath>("AssetPath");
    c_sys.funcStatic<&GetDataPath>("DataPath");

    // shell utils
    c_sys.funcStatic<&ChooseFile>("ChooseFile");
    c_sys.funcStatic<&ChooseFiles>("ChooseFiles");
    c_sys.funcStatic<&SaveFile>("SaveFile");
    c_sys.funcStatic<&PickFolder>("PickFolder");
    c_sys.funcStatic<&ShowLogFileContent>("ShowLogs");

    // date utils
    c_sys.funcStatic<&GetYesterday>("Yestoday");
    c_sys.funcStatic<&GetToday>("Today");
    c_sys.funcStatic<&GetTomorrow>("Tomorrow");

    // app utils
    c_sys.funcStatic<&CreateWorkItem>("CreateWork");
    c_sys.funcStatic<&CreateWorkItemWithNote>("CreateWorkWithNote");
    c_sys.funcStatic<&ShowStatistics>("ShowStatistics");

    // data ext
    c_sys.funcStatic<&System::GetIssueProjectDesc>("GetIssueProjectDesc");
}
